package com.sojson.util.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.datasource.DataSourceUtils;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.sojson.config.datasource.dynamic.datasource.CustomDynamicRoutingDataSource;
import com.sojson.config.datasource.enums.EDataSourceType;
import com.sojson.util.db.bean.DatabaseBean;
import com.sojson.util.db.interfaces.DatabaseUtilInterface;
import com.sojson.util.db.interfaces.impl.DatabaseUtilImpl;

import lombok.extern.slf4j.Slf4j;

/**
 * 数据源工具类
 * 
 * @author liu
 * @date 2022-01-18
 */
@Slf4j
public class DbUtil {

    private static final DatabaseUtilInterface DATABASE_UTIL_INTERFACE = DatabaseUtilImpl.getInstances();
    private static CustomDynamicRoutingDataSource dataSource;

    /** 获取当前线程的数据源 */
    public static String peek() {
        return DynamicDataSourceContextHolder.peek();
    }

    /** 获取当前线程的数据源 */
    public static DataSource peekDs() {
        return dataSource.determineDataSource();
    }

    /**
     * 设置当前线程的数据源
     * 
     * @param ds    数据源名称
     */
    public static void push(EDataSourceType dataSourceType) {
        push(dataSourceType.toString());
    }

    /**
     * 设置当前线程的数据源
     * 
     * @param ds    数据源名称
     */
    public static void push(String ds) {
        CustomDynamicRoutingDataSource.DATA_SOURCE.remove();
        DynamicDataSourceContextHolder.push(ds);
    }

    /** 清空当前线程的数据源 */
    public static void clear() {
        DynamicDataSourceContextHolder.clear();
        CustomDynamicRoutingDataSource.DATA_SOURCE.remove();
    }

    /**
     * 获取数据库类型
     * 
     * @return
     * @throws SQLException
     */
    public static String getDBType() throws SQLException {
        DataSource dataSource = DbUtil.peekDs();
        return getDBType(dataSource);
    }

    /**
     * 获取数据库类型
     * 
     * @param dataSource
     * @return
     * @throws SQLException
     */
    public static String getDBType(DataSource dataSource) throws SQLException {
        Connection connection = null;
        try {
            connection = DataSourceUtils.getConnection(dataSource);
            return getDBType(connection);
        } finally {
            DataSourceUtils.releaseConnection(connection, dataSource);
        }
    }

    /**
     * 获取数据库类型
     * 
     * @param connection
     * @return
     * @throws SQLException
     */
    public static String getDBType(Connection connection) throws SQLException {
        String databaseProduectName = connection.getMetaData().getDatabaseProductName();
        return databaseProduectName.toUpperCase();
    }

    /**
     * 执行Sql插入语句
     * 
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static int insert(String sql, Object obj[]) throws SQLException {
        return DATABASE_UTIL_INTERFACE.insert(sql, obj);
    }

    /**
     * 执行Sql插入语句(长连接)
     * 
     * @param conn 连接对象
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static int insert(DatabaseBean conn, String sql, Object obj[]) throws SQLException {
        return DATABASE_UTIL_INTERFACE.insert(conn, sql, obj);
    }

    /**
     * 执行Sql更新语句
     * 
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static int executeUpdate(String sql, Object obj[]) throws SQLException {
        return DATABASE_UTIL_INTERFACE.executeUpdate(sql, obj);
    }

    /**
     * 执行Sql更新语句(长连接)
     * 
     * @param conn 连接对象
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static int executeUpdate(DatabaseBean conn, String sql, Object obj[]) throws SQLException {
        return DATABASE_UTIL_INTERFACE.executeUpdate(conn, sql, obj);
    }

    /**
     * 执行Sql查询语句
     * 
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static List<HashMap<String, Object>> executeQuery(String sql, Object obj[]) throws SQLException {
        return DATABASE_UTIL_INTERFACE.executeQuery(sql, obj);
    }

    /**
     * 执行Sql查询语句(长连接)
     * 
     * @param conn 连接对象
     * @param sql Sql语句
     * @param obj 参数
     * @return
     * @throws SQLException
     */
    public static List<HashMap<String, Object>> executeQuery(DatabaseBean conn, String sql, Object obj[])
        throws SQLException {
        return DATABASE_UTIL_INTERFACE.executeQuery(conn, sql, obj);
    }

    /**
     * 获取连接对象
     * 
     * @return
     * @throws SQLException
     */
    public static DatabaseBean getConnection() throws SQLException {
        return DATABASE_UTIL_INTERFACE.getConnection();
    }

    /**
     * 获取连接对象
     * 
     * @param url 数据库路径
     * @param username 数据库帐号
     * @param password 数据库密码
     * @return
     * @throws SQLException
     */
    public static DatabaseBean getConnection(String url, String username, String password) throws SQLException {
        return DATABASE_UTIL_INTERFACE.getConnection(url, username, password);
    }

    /**
     * 获取连接对象
     * 
     * @param url 数据库路径
     * @param port 端口号
     * @param username 数据库帐号
     * @param password 数据库密码
     * @return
     * @throws SQLException
     */
    public static DatabaseBean getConnection(String url, int port, String username, String password)
        throws SQLException {
        return DATABASE_UTIL_INTERFACE.getConnection(url, port, username, password);
    }

    /**
     * 关闭连接(单个连接,顶级连接,比如:一级连接)
     * 
     * @param conn 要关闭的对象
     * @throws SQLException
     */
    public static void closeOne(DatabaseBean conn) throws SQLException {
        DATABASE_UTIL_INTERFACE.utilsCloseOne(conn);
    }

    /**
     * 关闭连接(一组连接,比如:一级连接,二级连接,三级连接...)
     * 
     * @param conn 要关闭的对象集合
     * @throws SQLException
     */
    public static void close(DatabaseBean conn) throws SQLException {
        DATABASE_UTIL_INTERFACE.utilsClose(conn);
    }

    /**
     * 关闭连接(多组连接,每组除顶级外都是List,顶级是一个Object,比如:顶级连接,{二级连接...},{三级连接...})
     * 
     * @param conn 要关闭的对象集合
     * @throws SQLException
     */
    public static void closeList(DatabaseBean conn) throws SQLException {
        DATABASE_UTIL_INTERFACE.utilsCloseList(conn);
    }

    public static void setDataSource(CustomDynamicRoutingDataSource dataSource) {
        DbUtil.dataSource = dataSource;
    }

}